home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Tk / generic / tkPreserve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-04  |  5.9 KB  |  232 lines

  1. /* 
  2.  * tkPreserve.c --
  3.  *
  4.  *    This file contains a collection of procedures that are used
  5.  *    to make sure that widget records and other data structures
  6.  *    aren't reallocated when there are nested procedures that
  7.  *    depend on their existence.
  8.  *
  9.  * Copyright (c) 1991-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16. static char sccsid[] = "@(#) tkPreserve.c 1.11 95/05/26 15:01:54";
  17.  
  18. #include "tkPort.h"
  19. #include "tk.h"
  20.  
  21. /*
  22.  * The following data structure is used to keep track of all the
  23.  * Tk_Preserve calls that are still in effect.  It grows as needed
  24.  * to accommodate any number of calls in effect.
  25.  */
  26.  
  27. typedef struct {
  28.     ClientData clientData;    /* Address of preserved block. */
  29.     int refCount;        /* Number of Tk_Preserve calls in effect
  30.                  * for block. */
  31.     int mustFree;        /* Non-zero means Tk_EventuallyFree was
  32.                  * called while a Tk_Preserve call was in
  33.                  * effect, so the structure must be freed
  34.                  * when refCount becomes zero. */
  35.     Tcl_FreeProc *freeProc;    /* Procedure to call to free. */
  36. } Reference;
  37.  
  38. static Reference *refArray;    /* First in array of references. */
  39. static int spaceAvl = 0;    /* Total number of structures available
  40.                  * at *firstRefPtr. */
  41. static int inUse = 0;        /* Count of structures currently in use
  42.                  * in refArray. */
  43. #define INITIAL_SIZE 2
  44.  
  45. /*
  46.  *----------------------------------------------------------------------
  47.  *
  48.  * Tk_Preserve --
  49.  *
  50.  *    This procedure is used by a procedure to declare its interest
  51.  *    in a particular block of memory, so that the block will not be
  52.  *    reallocated until a matching call to Tk_Release has been made.
  53.  *
  54.  * Results:
  55.  *    None.
  56.  *
  57.  * Side effects:
  58.  *    Information is retained so that the block of memory will
  59.  *    not be freed until at least the matching call to Tk_Release.
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63.  
  64. void
  65. Tk_Preserve(clientData)
  66.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  67. {
  68.     register Reference *refPtr;
  69.     int i;
  70.  
  71.     /*
  72.      * See if there is already a reference for this pointer.  If so,
  73.      * just increment its reference count.
  74.      */
  75.  
  76.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  77.     if (refPtr->clientData == clientData) {
  78.         refPtr->refCount++;
  79.         return;
  80.     }
  81.     }
  82.  
  83.     /*
  84.      * Make a reference array if it doesn't already exist, or make it
  85.      * bigger if it is full.
  86.      */
  87.  
  88.     if (inUse == spaceAvl) {
  89.     if (spaceAvl == 0) {
  90.         refArray = (Reference *) ckalloc((unsigned)
  91.             (INITIAL_SIZE*sizeof(Reference)));
  92.         spaceAvl = INITIAL_SIZE;
  93.     } else {
  94.         Reference *new;
  95.  
  96.         new = (Reference *) ckalloc((unsigned)
  97.             (2*spaceAvl*sizeof(Reference)));
  98.         memcpy((VOID *) new, (VOID *) refArray, spaceAvl*sizeof(Reference));
  99.         ckfree((char *) refArray);
  100.         refArray = new;
  101.         spaceAvl *= 2;
  102.     }
  103.     }
  104.  
  105.     /*
  106.      * Make a new entry for the new reference.
  107.      */
  108.  
  109.     refPtr = &refArray[inUse];
  110.     refPtr->clientData = clientData;
  111.     refPtr->refCount = 1;
  112.     refPtr->mustFree = 0;
  113.     inUse += 1;
  114. }
  115.  
  116. /*
  117.  *----------------------------------------------------------------------
  118.  *
  119.  * Tk_Release --
  120.  *
  121.  *    This procedure is called to cancel a previous call to
  122.  *    Tk_Preserve, thereby allowing a block of memory to be
  123.  *    freed (if no one else cares about it).
  124.  *
  125.  * Results:
  126.  *    None.
  127.  *
  128.  * Side effects:
  129.  *    If Tk_EventuallyFree has been called for clientData, and if
  130.  *    no other call to Tk_Preserve is still in effect, the block of
  131.  *    memory is freed.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. void
  137. Tk_Release(clientData)
  138.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  139. {
  140.     register Reference *refPtr;
  141.     int i;
  142.  
  143.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  144.     if (refPtr->clientData != clientData) {
  145.         continue;
  146.     }
  147.     refPtr->refCount--;
  148.     if (refPtr->refCount == 0) {
  149.         if (refPtr->mustFree) {
  150.         if ((refPtr->freeProc == TCL_DYNAMIC)
  151.             || (refPtr->freeProc == (Tcl_FreeProc *) free)) {
  152.             ckfree((char *) refPtr->clientData);
  153.         } else {
  154.             (*refPtr->freeProc)((char *) refPtr->clientData);
  155.         }
  156.         }
  157.  
  158.         /*
  159.          * Copy down the last reference in the array to fill the
  160.          * hole left by the unused reference.
  161.          */
  162.  
  163.         inUse--;
  164.         if (i < inUse) {
  165.         refArray[i] = refArray[inUse];
  166.         }
  167.     }
  168.     return;
  169.     }
  170.  
  171.     /*
  172.      * Reference not found.  This is a bug in the caller.
  173.      */
  174.  
  175.     panic("Tk_Release couldn't find reference for 0x%x", clientData);
  176. }
  177.  
  178. /*
  179.  *----------------------------------------------------------------------
  180.  *
  181.  * Tk_EventuallyFree --
  182.  *
  183.  *    Free up a block of memory, unless a call to Tk_Preserve is in
  184.  *    effect for that block.  In this case, defer the free until all
  185.  *    calls to Tk_Preserve have been undone by matching calls to
  186.  *    Tk_Release.
  187.  *
  188.  * Results:
  189.  *    None.
  190.  *
  191.  * Side effects:
  192.  *    Ptr may be released by calling free().
  193.  *
  194.  *----------------------------------------------------------------------
  195.  */
  196.  
  197. void
  198. Tk_EventuallyFree(clientData, freeProc)
  199.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  200.     Tcl_FreeProc *freeProc;    /* Procedure to actually do free. */
  201. {
  202.     register Reference *refPtr;
  203.     int i;
  204.  
  205.     /*
  206.      * See if there is a reference for this pointer.  If so, set its
  207.      * "mustFree" flag (the flag had better not be set already!).
  208.      */
  209.  
  210.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  211.     if (refPtr->clientData != clientData) {
  212.         continue;
  213.     }
  214.     if (refPtr->mustFree) {
  215.         panic("Tk_EventuallyFree called twice for 0x%x\n", clientData);
  216.         }
  217.         refPtr->mustFree = 1;
  218.     refPtr->freeProc = freeProc;
  219.         return;
  220.     }
  221.  
  222.     /*
  223.      * No reference for this block.  Free it now.
  224.      */
  225.  
  226.     if ((freeProc == TCL_DYNAMIC) || (freeProc == (Tcl_FreeProc *) free)) {
  227.     ckfree((char *) clientData);
  228.     } else {
  229.     (*freeProc)((char *)clientData);
  230.     }
  231. }
  232.